/*
 *  Copyright (c) 2013 Lincong All rights reserved.
 *  This software is the confidential and proprietary information of Lincong.
 *  You shall not disclose such Confidential
 *  Information and shall use it only in accordance with the terms of the license
 *  agreement you entered into with Lincong.
 *   Mail: Lincong <lincong1987@gmail.com>
 *     QQ: 159257119
 *  Phone: 15925711961
 *  This File Created On 2013-10-21 15:52:56.
 *  Document   : jquery.spinbox.js
 *  Encoding   : UTF-8
 *  $Id: jquery.spinbox.js 7 2014-01-08 09:34:48Z lc $
 */
/**
 * spinbox
 * jQuery spinbox插件
 * jQuery 1.7+
 * @author Arons
 * @version 0.1
 * @example : $('#example').spinbox({min: 0, max: 100, value:10});
 */

define(function (require) {

    var $ = require("jquery");

	require("../css/spinbox.css");


    $.fn.numberField = function (opts) {
        return $(this).each(function () {
            if (this.tagName.toLowerCase() != "input") {
                return;
            }
            if (typeof opts == "string") {
                var instance = $(this).data("_numberField");
                if (!instance) {
                    return;
                }
                var args = Array.prototype.slice.call(arguments, 1);
                if (typeof instance[opts] === "function") {
                    instance[opts].apply(instance, args);
                }
            } else {
                var instance = $(this).data("_numberField");
                if (instance) {
                    return;
                }
                instance = new $.NumberField($(this), opts);
                $(this).data("_numberField", instance);
            }
        });
    };
    $.NumberField = function (obj, opts) {
        this.input = obj;
        this.opts = $.extend(true, {}, $.NumberField.defaults, opts);
        this._init();
    };
    $.fn.getNumberField = function () {
        return $.NumberField.getNumberField(this);
    };
    $.NumberField.getNumberField = function (obj) {
        obj = $(obj);
        if (obj.length == 0) {
            return;
        } else if (obj.length == 1) {
            return obj.data("_numberField");
        } else if (obj.length > 1) {
            var array = [];
            obj.each(function (idx) {
                array.push(this.data("_numberField"));
            });
            return array;
        }
    };
    $.NumberField.prototype = {
        constructor: $.NumberField,
        _init: function () {
            var opts = this.opts, min = parseFloat(opts.min), max = parseFloat(opts.max), step = parseFloat(opts.step), precision = parseInt(opts.precision);
            this.min = !isNaN(min) ? min : Number.NEGATIVE_INFINITY;
            this.max = !isNaN(max) ? max : Number.MAX_VALUE;
            this.step = !isNaN(step) ? step : 1;
            this.precision = isNaN(precision) || !opts.decimal || precision < 0 ? 0 : precision;
            this.allowedReg = this._getAllowedReg();
            this.input.css("ime-mode", "disabled");
            this._initVal();
            this._initDisabled();
            this._bindEvent();
        },
        _getAllowedReg: function () {
            var opts = this.opts, allowed = "0123456789", reg;
            if (opts.decimal) {
                allowed += ".";
            }
            if (this.min < 0) {
                allowed += "-";
            }
            allowed = allowed.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
            reg = new RegExp("[" + allowed + "]");
            return reg;
        },
        _initVal: function () {
            var val = this._getProcessedVal(this.opts.value);
            if (val === false) {
                val = this._getProcessedVal(this.input.val());
                if (val === false) {
                    val = "";
                }
            }
            this._val = this.originVal = val;
            this.input.val(val);
        },
        _initDisabled: function () {
            var opts = this.opts;
            this._disabled = opts.disabled === true ? true : opts.disabled === false ? false : !!this.input.attr("disabled");
            this.originDisabled = this._disabled;
            this._handleDisabled(this._disabled);
        },
        _bindEvent: function () {
            var self = this, opts = self.opts;
            var KEYS = {
                up: 38,
                down: 40
            };
            var mouseWheel = $.browser.mozilla ? "DOMMouseScroll" : "mousewheel";
            this.input.on("keydown", function (e) {
                var which = e.which;
                if (which == KEYS.up || which == KEYS.down) {
                    if (!opts.keyEnable) {
                        return;
                    }
                    var operator = which == KEYS.up ? "plus" : "minus";
                    self._handleAdjusting(operator);
                    e.preventDefault();
                }
            }).on("keypress", function (e) {
                var charCode = typeof e.charCode != "undefined" ? e.charCode : e.keyCode;
                var keyChar = $.trim(String.fromCharCode(charCode));
                if (charCode != 0 && !self.allowedReg.test(keyChar)) {
                    e.preventDefault();
                }
            }).on("keyup", function (e) {
                self._clearAutoRepeat();
            }).on("focus", function (e) {
                self.focus = true;
            }).on("blur", function (e) {
                self.focus = false;
                //self.wrap.removeClass(opts.activeCls);
                var val = $.trim(self.input.val());
                //alert('blur')
                //self._clearAutoRepeat();
                if (val === self._val) {
                    return;
                }
                if (!self.setValue(val)) {
                    self.input.val(self._val);
                }
            }).on(mouseWheel, function (e) {
                e.preventDefault();
                if (!self.focus || !opts.wheelEnable) {
                    return;
                }
                e = e.originalEvent;
                var delta = e.wheelDelta ? e.wheelDelta / 120 : -e.detail / 3;
                var operator = delta == 1 ? "plus" : "minus";
                var val = self.input.val();
                if (val !== self._val && !self.setValue(val)) {
                    self.input.val(this._val);
                }
                self._adjustVal(operator);
            });
        },
        /**
         *对原始值进行处理
         *@return {false || string || number} 原始值为空返回''，为NaN返回false，为number返回处理好的数字
         */
        _getProcessedVal: function (val) {
            if (typeof val == "string" && $.trim(val) === "") {
                return "";
            }
            val = parseFloat(val);
            if (isNaN(val)) {
                return false;
            }
            val = val > this.max ? this.max : val < this.min ? this.min : val;
            val = val.toFixed(this.precision);
            if (!this.opts.forceDecimal) {
                val = parseFloat(val);
            }
            return val;
        },
        enable: function () {
            this._handleDisabled(false);
        },
        disable: function () {
            this._handleDisabled(true);
        },
        _handleDisabled: function (disabled) {
            var opts = this.opts;
            disabled === true ? this.input.addClass(opts.inputDisabledCls) : this.input.removeClass(opts.inputDisabledCls);
            this._disabled = disabled;
            this.input.attr("disabled", disabled);
        },
        /**
         *有微调发生时，对微调进行处理
         */
        _handleAdjusting: function (operator) {
            var val = this.input.val();
            if (val !== this._val && !this.setValue(val)) {
                this.input.val(this._val);
            }
            //已经到达最大值，最小值时
            if (this._val === this.max && operator == "plus" || this._val === this.min && operator == "minus") {
                return;
            }
            if (this.opts.autoRepeat) {
                this._clearAutoRepeat();
                this._setAutoRepeat(operator);
            }
            this._adjustVal(operator);
        },
        /**
         *微调值
         */
        _adjustVal: function (operator) {
            //已经到达最大值，最小值时
            if (this._val === this.max && operator == "plus" || this._val === this.min && operator == "minus") {
                this._clearAutoRepeat();
                return;
            }
            var baseVal = this._val !== "" ? this._val : this.min < 0 && this.min > Number.NEGATIVE_INFINITY ? this.min : 0;
            var val = operator == "plus" ? baseVal + this.step : baseVal - this.step;
            this.setValue(val);
        },
        _setAutoRepeat: function (operator) {
            var opts = this.opts, self = this;
            self.autoTimer = window.setTimeout(function () {
                self.autoRepeater = window.setInterval(function () {
                    self._adjustVal(operator);
                }, opts.interval);
            }, opts.delay);
        },
        _clearAutoRepeat: function () {
            if (this.autoTimer) {
                window.clearTimeout(this.autoTimer);
            }
            if (this.autoRepeater) {
                window.clearTimeout(this.autoRepeater);
            }
        },
        setValue: function (val) {
            var opts = this.opts;
            if (this._disabled) {
                return;
            }
            val = this._getProcessedVal(val);
            if (val === false) {
                return;
            }
            this.input.val(val);
            this._val = val;
            return true;
        }
    };
    $.NumberField.defaults = {
        value: undefined,
        max: undefined,
        min: undefined,
        step: 1,
        decimal: false,
        precision: 2,
        disabled: undefined,
        keyEnable: false,
        wheelEnable: false,
        autoRepeat: true,
        delay: 400,
        interval: 80,
        inputCls: "ui-input",
        inputDisabledCls: "ui-input-disabled"
    };

    /**
     * Spinbox插件 扩展自 NumberField
     * 带微调按钮的数字输入框
     */
    $.fn.spinbox = function (opts) {
        return $(this).each(function () {
            if (typeof opts == "string") {
                var instance = $(this).data("_spinbox");
                if (!instance) {
                    return;
                }
                var args = Array.prototype.slice.call(arguments, 1);
                if (typeof instance[opts] === "function") {
                    instance[opts].apply(instance, args);
                }
            } else {
                var instance = $(this).data("_spinbox");
                if (instance) {
                    return;
                }
                instance = new $.Spinbox($(this), opts);
                $(this).data("_spinbox", instance);
            }
        });
    };
    $.fn.getSpinbox = function () {
        return $.Spinbox.getSpinbox(this);
    };
    $.Spinbox = function (obj, opts) {
        this.obj = obj;
        this.opts = $.extend(true, {}, $.Spinbox.defaults, opts);
        this._init();
    };
    $.Spinbox.getSpinbox = function (obj) {
        obj = $(obj);
        if (obj.length == 0) {
            return;
        } else if (obj.length == 1) {
            return obj.data("_spinbox");
        } else if (obj.length > 1) {
            var array = [];
            obj.each(function (idx) {
                array.push(this.data("_spinbox"));
            });
            return array;
        }
    };
    $.Spinbox.prototype = {
        constructor: $.Spinbox,
        _init: function () {
            this._createStruture();
            this._initDisabled();
            this._bindEvent();
        },
        _createStruture: function () {
            var opts = this.opts, nextSibling, w = parseInt(opts.width), inputW;
            if (this.obj[0].tagName.toLowerCase() == "input") {
                this.input = this.obj;
                this.obj = this.obj.parent();
                nextSibling = this.input.next().length == 0 ? null : this.input.next();
            } else {
                this.input = $('<input type="text" />');
            }
            this.input.attr("autocomplete", "off").addClass(opts.inputCls).numberField(opts);
            this.numberField = this.input.data("_numberField");
            this.downBtn = $("<a />").addClass(opts.downBtnCls);
            this.upBtn = $("<a />").addClass(opts.upBtnCls);
            this.btnWrap = $("<span />").addClass(opts.btnWrapCls).append(this.upBtn, this.downBtn);
            this.btns = this.btnWrap.children();
            this.wrap = $("<span />").addClass(opts.wrapCls).append(this.input, this.btnWrap);
            if (nextSibling) {
                this.wrap.insertBefore(nextSibling);
            } else {
                this.wrap.appendTo(this.obj);
            }
            if (w) {
                this.wrap.width(w);
                inputW = w - this.btnWrap.outerWidth() - (this.input.outerWidth() - this.input.width());
                this.input.width(inputW);
            }
        },
        _initDisabled: function () {
            var opts = this.opts;
            this._disabled = opts.disabled === true ? true : opts.disabled === false ? false : undefined;
            if (this._disabled === undefined) {
                this._disabled = !!this.input.attr("disabled");
            }
            this.defaultDisabled = this._disabled;
            if (this._disabled === true) {
                this.disable();
            }
        },
        _bindEvent: function () {
            var self = this, opts = this.opts;
            this.wrap.on("mouseover", function (e) {
                if (self._disabled) {
                    return;
                }
                self.wrap.addClass(opts.hoverCls);
            }).on("mouseleave", function (e) {
                if (self._disabled) {
                    return;
                }
                self.wrap.removeClass(opts.hoverCls);
            });
            this.btnWrap.on("mouseover", function (e) {
                if (self._disabled) {
                    return;
                }
                $(this).addClass(opts.btnWrapHoverCls);
            }).on("mouseleave", function (e) {
                if (self._disabled) {
                    return;
                }
                $(this).removeClass(opts.btnWrapHoverCls);
            });
            //IE下需处理dblClick事件,IE9以下dblClick只执行一次click事件
            var clickEvent = $.browser.msie && parseInt($.browser.version) < 9 ? "mousedown dblclick" : "mousedown";
            this.btns.on(clickEvent, function (e) {
                if (self._disabled) {
                    return;
                }
                var operator = $(this)[0] == self.upBtn[0] ? "plus" : "minus";
                self.input.focus();
                if (e.type == "mousedown") {
                    self.numberField._handleAdjusting(operator);
                } else if (e.type == "dblclick") {
                    self.numberField._adjustVal(operator);
                }
                e.preventDefault();
            }).on("mouseup mouseleave", function (e) {
                self.numberField._clearAutoRepeat();
            });
            this.input.on("focus", function (e) {
                self.wrap.addClass(opts.activeCls);
            }).on("blur", function () {
                self.wrap.removeClass(opts.activeCls);
            });
            $(document).on("mousedown", function (e) {
                var target = e.target || e.srcElement;
                if ($(target).closest(self.wrap).length == 0) {
                    self.wrap.removeClass(opts.activeCls);
                }
            });
        },
        enable: function () {
            this._handleDisabled(false);
        },
        disable: function (disabled) {
            disabled = typeof disabled == "undefined" ? true : !!disabled;
            this._handleDisabled(disabled);
        },
        _handleDisabled: function (disabled) {
            var opts = this.opts;
            disabled === true ? this.wrap.addClass(opts.disabledCls) : this.wrap.removeClass(opts.disabledCls);
            this._disabled = disabled;
            this.numberField._handleDisabled(disabled);
        },
        getDisabled: function () {
            return this._disabled;
        },
        getValue: function () {
            this.numberField.getValue();
        },
        setValue: function (val) {
            return this.numberField.setValue(val);
        }
    };
    $.Spinbox.defaults = $.extend(true, $.NumberField.defaults, {
        /*min: undefined,
         max: undefined,
         step: 1, //每次增加的值
         value: undefined,
         width: undefined, //spinbox总宽
         disabled: undefined,
         keyEnable: true,
         wheelEnable: true,
         autoRepeat: true,
         delay: 400,
         interval: 50,*/
        width: undefined,
        wrapCls: "ui-spinbox-wrap",
        activeCls: "ui-spinbox-active",
        disabledCls: "ui-spinbox-disabled",
        hoverCls: "ui-spinbox-hover",
        inputCls: "input-txt",
        btnWrapCls: "btn-wrap",
        btnWrapHoverCls: "btn-wrap-hover",
        btnCls: "btn",
        downBtnCls: "btn-down",
        upBtnCls: "btn-up"
    });

});
